
/*-------------------------------------------------------------------------
 *
 * pg_class.h
 *	  "关系" 系统目录 (pg_class) 的定义
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/catalog/pg_class.h
 *
 * NOTES
 *	  Catalog.pm 模块读取此文件并推导模式
 *	  信息。
 *
 *-------------------------------------------------------------------------
 */
#ifndef PG_CLASS_H
#define PG_CLASS_H

#include "catalog/genbki.h"
#include "catalog/pg_class_d.h"

/* ----------------
 *		pg_class 定义。cpp 将其转换为
 *		typedef struct FormData_pg_class
 *
 * 注意，下面的 BKI_DEFAULT 值仅用于描述 BKI_BOOTSTRAP 
 * 目录的行，因为只有这些行出现在 pg_class.dat 中。
 * ----------------
 */
CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,RelationRelation_Rowtype_Id) BKI_SCHEMA_MACRO
{
	/* oid */
	Oid			oid;

	/* 类名 */
	NameData	relname;

	/* 包含此类的命名空间的 OID */
	Oid			relnamespace BKI_DEFAULT(pg_catalog) BKI_LOOKUP(pg_namespace);

	/* 对于关系的隐式行类型在 pg_type 中的条目的 OID（如果有） */
	Oid			reltype BKI_LOOKUP_OPT(pg_type);

	/* 对于基础复合类型在 pg_type 中的条目的 OID（如果有） */
	Oid			reloftype BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_type);

	/* 类所有者 */
	Oid			relowner BKI_DEFAULT(POSTGRES) BKI_LOOKUP(pg_authid);

	/* 访问方法；如果不是表/索引则为 0 */
	Oid			relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am);

	/* 物理存储文件的标识符 */
	/* relfilenode == 0 意味着它是一个“映射”关系，见 relmapper.c */
	Oid			relfilenode BKI_DEFAULT(0);

	/* 关系的表空间标识符（0 意味着数据库的默认值） */
	Oid			reltablespace BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_tablespace);

	/* 块数量（不总是最新） */
	int32		relpages BKI_DEFAULT(0);

	/* 元组数量（不总是最新；-1 意味着“未知”） */
	float4		reltuples BKI_DEFAULT(-1);

	/* 所有可见块的数量（不总是最新） */
	int32		relallvisible BKI_DEFAULT(0);

	/* toast 表的 OID；如果没有则为 0 */
	Oid			reltoastrelid BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class);

	/* T 如果具有（或曾经有过）任何索引 */
	bool		relhasindex BKI_DEFAULT(f);

	/* T 如果在多个数据库之间共享 */
	bool		relisshared BKI_DEFAULT(f);

	/* 见下面的 RELPERSISTENCE_xxx 常量 */
	char		relpersistence BKI_DEFAULT(p);

	/* 见下面的 RELKIND_xxx 常量 */
	char		relkind BKI_DEFAULT(r);

	/* 用户属性数量 */
	int16		relnatts BKI_DEFAULT(0);	/* genbki.pl 将在此填写 */

	/*
	 * 类 pg_attribute 必须包含恰好 "relnatts" 用户属性
	 * （attnums 范围从 1 到 relnatts）对于此类。它还可以包含
	 * 带有负 attnums 的系统属性条目。
	 */

	/* 类的 CHECK 约束数量 */
	int16		relchecks BKI_DEFAULT(0);

	/* 是否有（或曾经有）任何规则 */
	bool		relhasrules BKI_DEFAULT(f);

	/* 是否有（或曾经有）任何触发器 */
	bool		relhastriggers BKI_DEFAULT(f);

	/* 是否有（或曾经有）子表或索引 */
	bool		relhassubclass BKI_DEFAULT(f);

	/* 行安全性是否启用 */
	bool		relrowsecurity BKI_DEFAULT(f);

	/* 拥有者是否强制行安全性 */
	bool		relforcerowsecurity BKI_DEFAULT(f);

	/* 物化视图当前持有查询结果 */
	bool		relispopulated BKI_DEFAULT(t);

	/* 查看 REPLICA_IDENTITY_xxx 常量 */
	char		relreplident BKI_DEFAULT(n);

	/* 关系是否为分区？ */
	bool		relispartition BKI_DEFAULT(f);

	/* 在表重写期间链接到原始关系；否则为 0 */
	Oid			relrewrite BKI_DEFAULT(0) BKI_LOOKUP_OPT(pg_class);

	/* 所有 Xids 小于此值在该关系中被冻结 */
	TransactionId relfrozenxid BKI_DEFAULT(3);	/* FirstNormalTransactionId */

	/* 在该关系中的所有 multixacts 大于或等于此值；它实际上是一个 MultiXactId */
	TransactionId relminmxid BKI_DEFAULT(1);	/* FirstMultiXactId */

#ifdef CATALOG_VARLEN			/* 可变长度字段从这里开始 */
	/* 注意：这些字段在 relcache 项目的 rd_rel 字段中不存在。 */
	/* 访问权限 */
	aclitem		relacl[1] BKI_DEFAULT(_null_);

	/* 访问方法特定选项 */
	text		reloptions[1] BKI_DEFAULT(_null_);

	/* 分区边界节点树 */
	pg_node_tree relpartbound BKI_DEFAULT(_null_);
#endif
} FormData_pg_class;

/* pg_class 元组的固定部分大小，不包括可变长度字段 */
#define CLASS_TUPLE_SIZE \
	 (offsetof(FormData_pg_class,relminmxid) + sizeof(TransactionId))

/* ----------------
 *		Form_pg_class 对应于具有
 *		pg_class 关系格式的元组的指针。
 * ----------------
 */
typedef FormData_pg_class *Form_pg_class;

DECLARE_UNIQUE_INDEX_PKEY(pg_class_oid_index, 2662, ClassOidIndexId, on pg_class using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index, 2663, ClassNameNspIndexId, on pg_class using btree(relname name_ops, relnamespace oid_ops));
DECLARE_INDEX(pg_class_tblspc_relfilenode_index, 3455, ClassTblspcRelfilenodeIndexId, on pg_class using btree(reltablespace oid_ops, relfilenode oid_ops));

#ifdef EXPOSE_TO_CLIENT_CODE

#define		  RELKIND_RELATION		  'r'	/* 普通表 */
#define		  RELKIND_INDEX			  'i'	/* 二级索引 */
#define		  RELKIND_SEQUENCE		  'S'	/* 序列对象 */
#define		  RELKIND_TOASTVALUE	  't'	/* 用于非行内值 */
#define		  RELKIND_VIEW			  'v'	/* view */
#define		  RELKIND_MATVIEW		  'm'	/* 物化视图 */
#define		  RELKIND_COMPOSITE_TYPE  'c'	/* 复合类型 */
#define		  RELKIND_FOREIGN_TABLE   'f'	/* 外部表 */
#define		  RELKIND_PARTITIONED_TABLE 'p' /* 分区表 */
#define		  RELKIND_PARTITIONED_INDEX 'I' /* 分区索引 */

#define		  RELPERSISTENCE_PERMANENT	'p' /* 常规表 */
#define		  RELPERSISTENCE_UNLOGGED	'u' /* 不记录日志的永久表 */
#define		  RELPERSISTENCE_TEMP		't' /* 临时表 */

/* 副本身份的默认选择（主键或空） */
#define		  REPLICA_IDENTITY_DEFAULT	'd'
/* 此关系未记录副本身份 */
#define		  REPLICA_IDENTITY_NOTHING	'n'
/* 所有列都记录为副本身份 */
#define		  REPLICA_IDENTITY_FULL		'f'
 /*
 * 明确选择的候选键的列用作副本身份。
 * 请注意，如果索引已被删除，它仍然会被设置；在这种情况下，它
 * 的含义与“n”相同。
 */ 
#define		  REPLICA_IDENTITY_INDEX	'i'

/*
 * 具有物理存储的关系类型。这些关系通常具有
 * relfilenode 设置为非零，但如果关系被
 * 映射，它也可以是零。
 */ 
#define RELKIND_HAS_STORAGE(relkind) \
	((relkind) == RELKIND_RELATION || \
	 (relkind) == RELKIND_INDEX || \
	 (relkind) == RELKIND_SEQUENCE || \
	 (relkind) == RELKIND_TOASTVALUE || \
	 (relkind) == RELKIND_MATVIEW)

#define RELKIND_HAS_PARTITIONS(relkind) \
	((relkind) == RELKIND_PARTITIONED_TABLE || \
	 (relkind) == RELKIND_PARTITIONED_INDEX)

/*
 * 支持表空间的关系类型：具有存储的所有关系类型
 * 支持表空间，只是我们不支持将序列移动到
 * 不同的表空间。分区表和索引没有
 * 物理存储，但它们具有表空间设置，以便它们的
 * 子级可以继承它。
 */ 
#define RELKIND_HAS_TABLESPACE(relkind) \
	((RELKIND_HAS_STORAGE(relkind) || RELKIND_HAS_PARTITIONS(relkind)) \
	 && (relkind) != RELKIND_SEQUENCE)

/*
 * 具有表访问方法（rd_tableam）的关系类型。尽管序列
 * 使用堆表 AM，但在大多数用例中它们是一个特例，因此
 * 不包含在这里。
 */ 
#define RELKIND_HAS_TABLE_AM(relkind) \
	((relkind) == RELKIND_RELATION || \
	 (relkind) == RELKIND_TOASTVALUE || \
	 (relkind) == RELKIND_MATVIEW)

extern int	errdetail_relkind_not_supported(char relkind);

#endif							/* EXPOSE_TO_CLIENT_CODE */

#endif							/* PG_CLASS_H */
